#include "stdafx.h"

#include "parser_internal.h"
#include "parser_state.h"
#include "parser_errors.h"

#include "ast_modules.h"
#include "ast_namespaces.h"

namespace funpl
{

namespace parser
{

/// Parses a module name.
ast::module_identifier* parse_module_identifier(parser_state &state, ast::node *parent, bool implicitSemicolon)
{
	auto begin = state.tree->create_node<ast::module_identifier>(parent);

	// Name
	begin->name = expect(state, token_type::tok_identifier, implicitSemicolon).token.range;

	// Nested name
	while (accept_cont(state, token_type::op_period) || accept_cont(state, token_type::tok_op_colon))
		begin->nested = parse_module_identifier(state, parent, false);

	return begin;
}

/// Parses an import.
ast::import* parse_import(parser_state &state, ast::module *parent)
{
	expect_cont(state, token_type::kw_import);

	auto import = state.tree->create_node<ast::import>(parent);

	// Module name
	import->identifier = parse_module_identifier(state, import, false);

	return import;
}

/// Parses a module.
ast::module* parse_module(parser_state &state, ast::node *parent)
{
	auto module = state.tree->create_node<ast::module>(parent);

	// Named module
	if (accept_is(state, token_type::kw_module))
		module->identifier = parse_module_identifier(state, module, false);

	// Imports
	while (check_is(state, token_type::kw_import))
		module->imports.push_back( parse_import(state, module) );

	// Global namespace
	module->global = state.tree->create_node<ast::namespace_>(module);
	
	// Error / retry loop
	while (state.token.type != token_type::end)
	{
		try
		{
			// Global namespace body
			maybe_parse_namespace_body(state, module->global);

			// Make sure full namespace has been parsed
			expect(state, token_type::end);
		}
		catch(const parse_exception&) { skip_error(state); }
	}

	return module;
}

} // namespace

} // namespace